home *** CD-ROM | disk | FTP | other *** search
- /*
- * Program: IMAP2 server
- *
- * Author: Mark Crispin
- * Networks and Distributed Computing
- * Computing & Communications
- * University of Washington
- * Administration Building, AG-44
- * Seattle, WA 98195
- * Internet: MRC@CAC.Washington.EDU
- *
- * Date: 5 November 1990
- * Last Edited: 13 May 1992
- *
- * Copyright 1992 by the University of Washington
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted, provided
- * that the above copyright notice appears in all copies and that both the
- * above copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the University of Washington not be
- * used in advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission. This software is made
- * available "as is", and
- * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
- * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
- * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
- * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
- * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
- /* Parameter files */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <netdb.h>
- #include <errno.h>
- #include <signal.h>
- #include <pwd.h>
- #include <sys/types.h>
- #include <sys/file.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <sys/dir.h> /* makes news.h happy */
- #include "osdep.h"
- #include "mail.h"
- #include "misc.h"
- #include "news.h" /* moby sigh */
-
-
- /* Autologout timer */
- #define TIMEOUT 60*30
-
-
- /* Size of temporary buffers */
- #define TMPLEN 8192
-
-
- /* Server states */
-
- #define LOGIN 0
- #define SELECT 1
- #define OPEN 2
- #define LOGOUT 3
-
- /* Global storage */
-
- char *version = "6.6(43)"; /* version number of this server */
- struct itimerval timer; /* timeout state */
- int state = LOGIN; /* server state */
- int mackludge = 0; /* MacMS kludge */
- int anonymous = 0; /* non-zero if anonymous */
- MAILSTREAM *stream = NIL; /* mailbox stream */
- long nmsgs = 0; /* number of messages */
- long recent = 0; /* number of recent messages */
- char *host = NIL; /* local host name */
- char *user = NIL; /* user name */
- char *pass = NIL; /* password */
- char *home = NIL; /* home directory */
- char *flags = NIL; /* flag text */
- char cmdbuf[TMPLEN]; /* command buffer */
- char *tag; /* tag portion of command */
- char *cmd; /* command portion of command */
- char *arg; /* pointer to current argument of command */
- char *lsterr = NIL; /* last error message from c-client */
- char *response = NIL; /* command response */
-
-
- /* Response texts */
-
- char *win = "%s OK %s completed\015\012";
- char *altwin = "%s OK %s\015\012";
- char *rowin = "%s OK [READ-ONLY] %s completed\015\012";
- char *rwwin = "%s OK [READ-WRITE] %s completed\015\012";
- char *lose = "%s NO %s failed: %s\015\012";
- char *misarg = "%s BAD Missing required argument to %s\015\012";
- char *badarg = "%s BAD Argument given to %s when none expected\015\012";
- char *badseq = "%s BAD Bogus sequence in %s\015\012";
- char *badatt = "%s BAD Bogus attribute list in %s\015\012";
- char *badlit = "%s BAD Bogus literal count in %s\015\012";
- char *toobig = "* BAD Command line too long\015\012";
- char *nulcmd = "* BAD Null command\015\012";
- char *argrdy = "+ Ready for argument\015\012";
-
- /* Drivers we use */
-
- extern DRIVER bezerkdriver,tenexdriver,imapdriver,newsdriver,dummydriver;
-
-
- /* Function prototypes */
-
- void main ();
- void clkint ();
- char *snarf ();
- void fetch ();
- void fetch_body ();
- void fetch_body_part ();
- void fetch_envelope ();
- void fetch_encoding ();
- void changed_flags ();
- void fetch_flags ();
- void fetch_internaldate ();
- void fetch_rfc822 ();
- void fetch_rfc822_header ();
- void fetch_rfc822_size ();
- void fetch_rfc822_text ();
- void penv ();
- void pbody ();
- void pstring ();
- void paddr ();
- long cstring ();
- long caddr ();
-
- extern char *crypt ();
-
- /* Main program */
-
- void main (argc,argv)
- int argc;
- char *argv[];
- {
- int i;
- char *s,*t = "OK",*u,*v;
- struct hostent *hst;
- void (*f) () = NIL;
- mail_link (&tenexdriver); /* install the Tenex mail driver */
- mail_link (&bezerkdriver); /* install the Berkeley mail driver */
- mail_link (&imapdriver); /* install the IMAP driver */
- mail_link (&newsdriver); /* install the netnews driver */
- mail_link (&dummydriver); /* install the dummy driver */
- gethostname (cmdbuf,TMPLEN-1);/* get local name */
- host = cpystr ((hst = gethostbyname (cmdbuf)) ? hst->h_name : cmdbuf);
- rfc822_date (cmdbuf); /* get date/time now */
- if ((i = getuid ()) > 0) { /* logged in? */
- if (!(s = (char *) getlogin ())) s = (getpwuid (i))->pw_name;
- user = cpystr (s); /* set up user name */
- pass = cpystr ("*"); /* and fake password */
- state = SELECT; /* enter select state */
- t = "PREAUTH"; /* pre-authorized */
- }
- printf ("* %s %s IMAP2+ Service %s at %s\015\012",t,host,version,cmdbuf);
- fflush (stdout); /* dump output buffer */
- signal (SIGALRM,clkint); /* prepare for clock interrupt */
- /* initialize timeout interval */
- timer.it_interval.tv_sec = TIMEOUT;
- timer.it_interval.tv_usec = 0;
- do { /* command processing loop */
- /* get a command under timeout */
- timer.it_value.tv_sec = TIMEOUT; timer.it_value.tv_usec = 0;
- setitimer (ITIMER_REAL,&timer,NIL);
- if (!fgets (cmdbuf,TMPLEN-1,stdin)) _exit (1);
- /* make sure timeout disabled */
- timer.it_value.tv_sec = timer.it_value.tv_usec = 0;
- setitimer (ITIMER_REAL,&timer,NIL);
- fs_give ((void **) &lsterr);/* no last error */
- /* find end of line */
- if (!strchr (cmdbuf,'\012')) printf (toobig);
- else if (!(tag = strtok (cmdbuf," \015\012"))) printf (nulcmd);
- else if (!(cmd = strtok (NIL," \015\012")))
- printf ("%s BAD Missing command\015\012",tag);
- else { /* parse command */
- response = win; /* set default response */
- ucase (cmd); /* canonicalize command case */
- /* snarf argument */
- arg = strtok (NIL,"\015\012");
- /* LOGOUT command always valid */
- if (!strcmp (cmd,"LOGOUT")) {
- if (state == OPEN) mail_close (stream);
- stream = NIL;
- printf ("* BYE %s IMAP2 server terminating connection\015\012",host);
- state = LOGOUT;
- }
-
- /* kludge for MacMS */
- else if (!strcmp (cmd,"VERSION")) {
- /* single argument */
- if (!(s = snarf (&arg))) response = misarg;
- else if (arg) response = badarg;
- else {
- if (!((i = atoi (s)) && i > 0 && i <= 4))
- response = "%s BAD Unknown version\015\012";
- else if (mackludge = (i == 4))
- printf ("* OK The MacMS kludge is enabled\015\012");
- }
- }
- else if (!strcmp (cmd,"NOOP")) {
- if ((state == OPEN) && !mail_ping (stream)) {
- printf ("* BYE %s Fatal mailbox error: %s\015\012",host,
- lsterr ? lsterr : "<unknown>");
- state = LOGOUT; /* go away */
- }
- }
- else switch (state) { /* dispatch depending upon state */
- case LOGIN: /* waiting to get logged in */
- if (!strcmp (cmd,"LOGIN")) {
- struct stat sbuf;
- struct passwd *pwd;
- fs_give ((void **) &user);
- fs_give ((void **) &pass);
- /* two arguments */
- if (!((user = cpystr (snarf (&arg))) &&
- (pass = cpystr (snarf (&arg))))) response = misarg;
- else if (arg) response = badarg;
- /* see if username and password are OK */
- else if (server_login (user,pass,&home)) state = SELECT;
- /* nope, see if we allow anonymous */
- else if (!stat ("/etc/anonymous.newsgroups",&sbuf) &&
- !strcmp (user,"anonymous") && (pwd = getpwnam ("nobody"))) {
- anonymous = T; /* note we are anonymous, login as nobody */
- setgid (pwd->pw_gid);
- setuid (pwd->pw_uid);
- state = SELECT; /* make selected */
- }
- else response = "%s NO Bad %s user name and/or password\015\012";
- }
- else response = "%s BAD Command unrecognized/login please: %s\015\012";
- break;
-
- case OPEN: /* valid only when mailbox open */
- /* fetch mailbox attributes */
- if (!strcmp (cmd,"FETCH")) {
- if (!((s = strtok (arg," ")) && (t = strtok (NIL,"\015\012"))))
- response = misarg;
- else fetch (s,t); /* do the fetch */
- }
- /* store mailbox attributes */
- else if (!strcmp (cmd,"STORE")) {
- /* must have three arguments */
- if (!((s = strtok (arg," ")) && (cmd = strtok (NIL," ")) &&
- (t = strtok (NIL,"\015\012")))) response = misarg;
- else if (!strcmp (ucase (cmd),"+FLAGS")) f = mail_setflag;
- else if (!strcmp (cmd,"-FLAGS")) f = mail_clearflag;
- else if (!strcmp (cmd,"FLAGS")) {
- mail_clearflag (stream,s,flags);
- f = mail_setflag; /* gross, but rarely if ever done */
- }
- else response = "%s BAD STORE %s not yet implemented\015\012";
- if (f) { /* if a function was selected */
- (*f) (stream,s,t); /* do it */
- fetch (s,"FLAGS"); /* get the new flags status */
- }
- }
- /* check for new mail */
- else if (!strcmp (cmd,"CHECK")) {
- /* no arguments */
- if (arg) response = badarg;
- else if (anonymous) mail_ping (stream);
- else mail_check (stream);
- }
- /* expunge deleted messages */
- else if (!(anonymous || strcmp (cmd,"EXPUNGE"))) {
- /* no arguments */
- if (arg) response = badarg;
- else mail_expunge (stream);
- }
- /* copy message(s) */
- else if (!(anonymous || strcmp (cmd,"COPY"))) {
- if (!((s = snarf (&arg)) && (t = snarf (&arg)))) response = misarg;
- else if (arg) response = badarg;
- else mail_copy (stream,s,t);
- }
-
- /* search mailbox */
- else if (!strcmp (cmd,"SEARCH")) {
- /* one or more arguments required */
- if (!arg) response = misarg;
- else { /* zap search vector */
- /* end with a literal argument? */
- while ((*(t = arg + strlen (arg) - 1) == '}') &&
- (s = strrchr (arg,'{')) && response == win) {
- /* get length of literal, validate */
- if (((i = atoi (++s)) < 1) || (TMPLEN - (t++ - cmdbuf) < i + 10))
- response = badlit;
- else {
- *t++ = '\015'; /* reappend CR/LF */
- *t++ = '\012';
- printf (argrdy);/* tell client ready for argument */
- /* copy the literal */
- while (i--) *t++ = getchar ();
- /* start a timeout */
- timer.it_value.tv_sec = TIMEOUT; timer.it_value.tv_usec = 0;
- setitimer (ITIMER_REAL,&timer,NIL);
- /* get new command tail */
- if (!fgets (t,TMPLEN - (t-cmdbuf) - 1,stdin)) _exit (1);
- /* clear timeout */
- timer.it_value.tv_sec = timer.it_value.tv_usec = 0;
- setitimer (ITIMER_REAL,&timer,NIL);
- /* find end of line */
- if (!(s = strchr (t,'\012'))) response = toobig;
- else {
- *s = NIL; /* tie off line */
- if (*--s == '\015') *s = NIL;
- }
- }
- }
- /* punt if error */
- if (response != win) break;
- /* do the search */
- mail_search (stream,arg);
- if (response == win || response == altwin) {
- /* output search results */
- fputs ("* SEARCH",stdout);
- for (i = 1; i <= nmsgs; ++i)
- if (mail_elt (stream,i)->searched) printf (" %d",i);
- fputs ("\015\012",stdout);
- }
- }
- }
- else /* fall into select case */
-
- case SELECT: /* valid whenever logged in */
- /* select new mailbox */
- if ((!(anonymous || strcmp (cmd,"SELECT"))) ||
- (!strcmp (cmd,"BBOARD"))) {
- /* single argument */
- if (!(s = snarf (&arg))) response = misarg;
- else if (arg) response = badarg;
- else {
- char tmp[MAILTMPLEN];
- sprintf (tmp,"%s%s",(*cmd == 'B') ? "*" : "",s);
- recent = -1; /* make sure we get an update */
- if ((stream = mail_open (stream,tmp,anonymous ? 69 : NIL)) &&
- ((response == win) || (response == altwin))) {
- /* flush old list */
- fs_give ((void **) &flags);
- *s = '('; /* start new flag list over old file name */
- s[1] = '\0';
- for (i = 0; i < NUSERFLAGS; i++)
- if (t = stream->user_flags[i]) strcat (strcat (s,t)," ");
- /* append system flags to list */
- strcat (s,"\\Answered \\Flagged \\Deleted \\Seen)");
- /* output list of flags */
- printf ("* FLAGS %s\015\012",(flags = cpystr (s)));
- state = OPEN;
- /* note readonly/readwrite */
- response = stream->readonly ? rowin : rwwin;
- }
- else { /* nuke if still open */
- if (stream) mail_close (stream);
- stream = NIL;
- state = SELECT; /* no mailbox open now */
- response = lose; /* open failed */
- }
- }
- }
-
- /* find mailboxes or bboards */
- else if (!strcmp (cmd,"FIND")) {
- /* get subcommand and true argument */
- if (!((s = strtok (arg," \015\012")) && (cmd = ucase (s)) &&
- (arg = strtok (NIL,"\015\012")) && (s = snarf (&arg))))
- response = misarg; /* missing required argument */
- else if (arg) response = badarg;
- else { /* dispatch */
- if (!(anonymous || strcmp (cmd,"MAILBOXES"))) {
- mail_find (NIL,s);/* default find action */
- if (stream && *stream->mailbox == '{') mail_find (stream,s);
- }
- /* find bulletin boards */
- else if (!strcmp (cmd,"BBOARDS")) {
- if (anonymous) { /* special version for anonymous users */
- struct stat sbuf;
- if (!(stat (NEWSSPOOL,&sbuf) || stat (ACTIVEFILE,&sbuf)) &&
- ((i = open (ACTIVEFILE,O_RDONLY,NIL)) >= 0)) {
- /* get file size and read data */
- fstat (i,&sbuf);
- read (i,v = (char *) fs_get (sbuf.st_size+1),sbuf.st_size);
- close (i); /* close file */
- /* tie off string */
- v[sbuf.st_size] = '\0';
- if (t = strtok (v,"\n")) do if (u = strchr (t,' ')) {
- *u = '\0'; /* tie off at end of name */
- if (pmatch (lcase (t),s)) mm_bboard (t);
- } while (t = strtok (NIL,"\n"));
- fs_give ((void **) &v);
- }
- }
- else { /* allow the ordinary driver version */
- mail_find_bboards (NIL,s);
- if (stream && *stream->mailbox == '{')
- mail_find_bboards (stream,s);
- }
- }
- else response = "%s BAD Command unrecognized: FIND %s\015\012";
- }
- }
-
- else response = "%s BAD Command unrecognized: %s\015\012";
- break;
- default:
- response = "%s BAD Server in unknown state for %s command\015\012";
- break;
- }
- /* change in recent messages? */
- if ((state == OPEN) && (recent != stream->recent))
- printf ("* %d RECENT\015\012",(recent = stream->recent));
- /* get text for alternative win message now */
- if (response == altwin) cmd = lsterr;
- /* output response */
- printf (response,tag,cmd,lsterr);
- }
- fflush (stdout); /* make sure output blatted */
- } while (state != LOGOUT); /* until logged out */
- exit (0); /* all done */
- }
-
-
- /* Clock interrupt
- */
-
- void clkint ()
- {
- printf ("* BYE Autologout; idle for too long\015\012");
- fflush (stdout); /* make sure output blatted */
- /* try to gracefully close the stream */
- if (state == OPEN) mail_close (stream);
- stream = NIL;
- exit (0); /* die die die */
- }
-
- /* Snarf an argument
- * Accepts: pointer to argument text pointer
- * Returns: argument
- */
-
- char *snarf (arg)
- char **arg;
- {
- long i;
- char *c = *arg;
- char *s = c + 1;
- char *t = NIL;
- if (!c) return NIL; /* better be an argument */
- switch (*c) { /* see what the argument is */
- case '\0': /* catch bogons */
- case ' ':
- return NIL;
- case '"': /* quoted string */
- if (!(strchr (s,'"') && (c = strtok (c,"\"")))) return NIL;
- break;
- case '{': /* literal string */
- if (isdigit (*s)) { /* be sure about that */
- i = strtol (s,&c,10); /* get its length */
- /* validate end of literal */
- if (*c++ != '}' || *c++) return NIL;
- if ((i + 10) > (TMPLEN - (c - cmdbuf))) return NIL;
- printf (argrdy); /* tell client ready for argument */
- t = c; /* get it */
- while (i--) *t++ = getchar ();
- *t++ = NIL; /* make sure string tied off */
- /* start timeout */
- timer.it_value.tv_sec = TIMEOUT; timer.it_value.tv_usec = 0;
- setitimer (ITIMER_REAL,&timer,NIL);
- /* get new command tail */
- if (!fgets ((*arg = t),TMPLEN - (t - cmdbuf) - 1,stdin)) _exit (1);
- /* clear timeout */
- timer.it_value.tv_sec = timer.it_value.tv_usec = 0;
- setitimer (ITIMER_REAL,&timer,NIL);
- if (!strchr (t,'\012')) { /* have a newline there? */
- response = toobig; /* lost it seems */
- return NIL;
- }
- break;
- }
- /* otherwise fall through (third party IMAP) */
- default: /* atomic string */
- c = strtok (*arg," \015\012");
- break;
- }
- /* remainder of arguments */
- if ((*arg = strtok (t,"\015\012")) && **arg == ' ') ++*arg;
- return c;
- }
-
- /* Fetch message data
- * Accepts: sequence as a string
- * string of data items to be fetched
- */
-
- #define MAXFETCH 100
-
- void fetch (s,t)
- char *s;
- char *t;
- {
- char c,*v;
- long i,k;
- void (*f[MAXFETCH]) ();
- char *fa[MAXFETCH];
- if (!mail_sequence (stream,s)) {
- response = badseq; /* punt if sequence bogus */
- return;
- }
- /* process macros */
- if (!strcmp (ucase (t),"ALL"))
- strcpy (t,"(FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)");
- else if (!strcmp (t,"FULL"))
- strcpy (t,"(FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY)");
- else if (!strcmp (t,"FAST")) strcpy (t,"(FLAGS INTERNALDATE RFC822.SIZE)");
- s = t + strlen (t) - 1; /* last character in attribute string */
- /* if multiple items, make sure in list form */
- if (strchr (t,' ') && ((*t != '(') || (*s != ')'))) {
- response = badatt;
- return;
- }
- /* nuke the parens now */
- if ((*t == '(') && (*s == ')') && t++) *s = '\0';
- k = 0; /* initial index */
- if (s = strtok (t," ")) do { /* parse attribute list */
- if (*s == 'B' && s[1] == 'O' && s[2] == 'D' && s[3] == 'Y') switch (s[4]) {
- case '\0': /* entire body */
- f[k++] = fetch_body;
- break;
- case '[': /* body segment */
- if ((v = strchr (s + 5,']')) && (!(*v = v[1]))) {
- fa[k] = s + 5; /* set argument */
- f[k++] = fetch_body_part;
- break; /* valid body segment */
- } /* else fall into default case */
- default: /* bogus */
- response = badatt;
- return;
- }
- else
- if (!strcmp (s,"ENVELOPE")) f[k++] = fetch_envelope;
- else if (!strcmp (s,"FLAGS")) f[k++] = fetch_flags;
- else if (!strcmp (s,"INTERNALDATE")) f[k++] = fetch_internaldate;
- else if (!strcmp (s,"RFC822")) f[k++] = fetch_rfc822;
- else if (!strcmp (s,"RFC822.HEADER")) f[k++] = fetch_rfc822_header;
- else if (!strcmp (s,"RFC822.SIZE")) f[k++] = fetch_rfc822_size;
- else if (!strcmp (s,"RFC822.TEXT")) f[k++] = fetch_rfc822_text;
- else { /* unknown attribute */
- response = badatt;
- return;
- }
- } while ((s = strtok (NIL," ")) && k < MAXFETCH);
- else {
- response = misarg; /* missing attribute list */
- return;
- }
- if (s) { /* too many attributes? */
- response = "%s BAD Excessively complex FETCH attribute list\015\012";
- return;
- }
- f[k++] = NIL; /* tie off attribute list */
- /* for each requested message */
- for (i = 1; i <= nmsgs; i++) if (mail_elt (stream,i)->sequence) {
- /* parse envelope, set body, do warnings */
- mail_fetchenvelope (stream,i);
- printf ("* %d FETCH (",i); /* leader */
- (*f[0]) (i,fa[0]); /* do first attribute */
- for (k = 1; f[k]; k++) { /* for each subsequent attribute */
- putchar (' '); /* delimit with space */
- (*f[k]) (i,fa[k]); /* do that attribute */
- }
- fputs (")\015\012",stdout); /* trailer */
- }
- }
-
- /* Fetch message body structure
- * Accepts: message number
- * string argument
- */
-
-
- void fetch_body (i,s)
- long i;
- char *s;
- {
- BODY *body;
- mail_fetchenvelope (stream,i);/* make sure have envelope */
- fputs ("BODY ",stdout); /* output attribute */
- /* output body */
- if (body = mail_elt (stream,i)->body) pbody (body);
- else fputs ("NIL",stdout); /* no body */
- }
-
-
- /* Fetch message body part
- * Accepts: message number
- * string argument
- */
-
- void fetch_body_part (i,s)
- long i;
- char *s;
- {
- unsigned long j;
- long k = 0;
- MESSAGECACHE *elt = mail_elt (stream,i);
- int f = elt->seen;
- printf ("BODY[%s] ",s); /* output attribute */
- if (elt->body && (s = mail_fetchbody (stream,i,s,&j))) {
- /* and literal string */
- printf ("{%d}\015\012",j);
- while (j -= k) k = fwrite (s += k,1,j,stdout);
- changed_flags (i,f); /* output changed flags */
- }
- else fputs ("NIL",stdout); /* can't output anything at all */
- }
-
- /* Fetch IMAP envelope
- * Accepts: message number
- * string argument
- */
-
- void fetch_envelope (i,s)
- long i;
- char *s;
- {
- ENVELOPE *env = mail_fetchenvelope (stream,i);
- fputs ("ENVELOPE ",stdout); /* output attribute */
- if (env) { /* have an envelope? */
- /* disgusting MacMS kludge */
- if (mackludge) printf ("%d ",cstring (env->date) + cstring (env->subject) +
- caddr (env->from) + caddr (env->sender) +
- caddr (env->reply_to) + caddr (env->to) +
- caddr (env->cc) + caddr (env->bcc) +
- cstring (env->in_reply_to) +
- cstring (env->message_id));
- penv (env); /* output envelope */
- }
- else fputs ("NIL",stdout); /* no envelope */
- }
-
- /* Fetch flags
- * Accepts: message number
- * string argument
- */
-
- void fetch_flags (i,s)
- long i;
- char *s;
- {
- char tmp[MAILTMPLEN];
- long u;
- char *t;
- MESSAGECACHE *elt = mail_elt (stream,i);
- s = tmp;
- s[0] = s[1] = '\0'; /* start with empty flag string */
- /* output system flags */
- if (elt->recent) strcat (s," \\Recent");
- if (elt->seen) strcat (s," \\Seen");
- if (elt->deleted) strcat (s," \\Deleted");
- if (elt->flagged) strcat (s," \\Flagged");
- if (elt->answered) strcat (s," \\Answered");
- if (u = elt->user_flags) do /* any user flags? */
- if ((TMPLEN - ((s += strlen (s)) - tmp)) >
- (2 + strlen (t = stream->user_flags[find_rightmost_bit (&u)]))) {
- *s++ = ' '; /* space delimiter */
- strcpy (s,t); /* copy the user flag */
- }
- while (u); /* until no more user flags */
- printf ("FLAGS (%s)",tmp+1); /* output results, skip first char of list */
- }
-
-
- /* Output flags if was unseen
- * Accepts: message number
- * prior value of Seen flag
- */
-
- void changed_flags (i,f)
- long i;
- int f;
- {
- if (!f) { /* was unseen? */
- putchar (' '); /* yes, delimit with space */
- fetch_flags (i,NIL); /* output flags */
- }
- }
-
-
- /* Fetch message internal date
- * Accepts: message number
- * string argument
- */
-
- void fetch_internaldate (i,s)
- long i;
- char *s;
- {
- printf ("INTERNALDATE \"%s\"",mail_elt (stream,i)->internal_date);
- }
-
- /* Fetch complete RFC-822 format message
- * Accepts: message number
- * string argument
- */
-
- void fetch_rfc822 (i,s)
- long i;
- char *s;
- {
- int f = mail_elt (stream,i)->seen;
- printf ("RFC822 {%d}\015\012%s",mail_elt (stream,i)->rfc822_size,
- mail_fetchheader (stream,i));
- fputs (mail_fetchtext (stream,i),stdout);
- changed_flags (i,f); /* output changed flags */
- }
-
-
- /* Fetch RFC-822 header
- * Accepts: message number
- * string argument
- */
-
- void fetch_rfc822_header (i,s)
- long i;
- char *s;
- {
- fputs ("RFC822.HEADER ",stdout);
- pstring (mail_fetchheader (stream,i));
- }
-
-
- /* Fetch RFC-822 message length
- * Accepts: message number
- * string argument
- */
-
- void fetch_rfc822_size (i,s)
- long i;
- char *s;
- {
- printf ("RFC822.SIZE %d",mail_elt (stream,i)->rfc822_size);
- }
-
-
- /* Fetch RFC-822 text only
- * Accepts: message number
- * string argument
- */
-
- void fetch_rfc822_text (i,s)
- long i;
- char *s;
- {
- int f = mail_elt (stream,i)->seen;
- fputs ("RFC822.TEXT ",stdout);
- pstring (mail_fetchtext (stream,i));
- changed_flags (i,f); /* output changed flags */
- }
-
- /* Print envelope
- * Accepts: body
- */
-
- void penv (env)
- ENVELOPE *env;
- {
- putchar ('('); /* delimiter */
- pstring (env->date); /* output envelope fields */
- putchar (' ');
- pstring (env->subject);
- putchar (' ');
- paddr (env->from);
- putchar (' ');
- paddr (env->sender);
- putchar (' ');
- paddr (env->reply_to);
- putchar (' ');
- paddr (env->to);
- putchar (' ');
- paddr (env->cc);
- putchar (' ');
- paddr (env->bcc);
- putchar (' ');
- pstring (env->in_reply_to);
- putchar (' ');
- pstring (env->message_id);
- putchar (')'); /* end of envelope */
- }
-
- /* Print body
- * Accepts: body
- */
-
- void pbody (body)
- BODY *body;
- {
- PARAMETER *param;
- PART *part;
- putchar ('('); /* delimiter */
- /* multipart type? */
- if (body->type == TYPEMULTIPART) {
- for (part = body->contents.part; part; part = part->next)
- pbody (&(part->body)); /* print each part */
- putchar (' '); /* space delimiter */
- pstring (body->subtype); /* and finally the subtype */
- }
- else { /* non-multipart body type */
- pstring ((char *) body_types[body->type]);
- putchar (' ');
- pstring (body->subtype);
- if (param = body->parameter) {
- fputs (" (",stdout);
- do {
- pstring (param->attribute);
- putchar (' ');
- pstring (param->value);
- if (param = param->next) putchar (' ');
- } while (param);
- fputs (") ",stdout);
- }
- else fputs (" NIL ",stdout);
- pstring (body->id);
- putchar (' ');
- pstring (body->description);
- putchar (' ');
- pstring ((char *) body_encodings[body->encoding]);
- printf (" %d",body->size.bytes);
- switch (body->type) { /* extra stuff depends upon body type */
- case TYPEMESSAGE:
- /* can't do this if not RFC822 */
- if (strcmp (body->subtype,"RFC822")) break;
- putchar (' ');
- penv (body->contents.msg.env);
- putchar (' ');
- pbody (body->contents.msg.body);
- case TYPETEXT:
- printf (" %d",body->size.lines);
- break;
- default:
- break;
- }
- }
- putchar (')'); /* end of body */
- }
-
- /* Print string
- * Accepts: string
- */
-
- void pstring (s)
- char *s;
- {
- char c,*t;
- if (t = s) { /* is there a string? */
- /* yes, search for specials */
- while (c = *t++) if (c == '"' || c == '{' || c == '\015' || c == '\012' ||
- c == '%' || c == '\\') break;
- /* must use literal string */
- if (c) printf ("{%d}\015\012%s",strlen (s),s);
- else printf ("\"%s\"",s); /* may use quoted string */
- }
- else fputs ("NIL",stdout); /* empty string */
- }
-
-
- /* Print address list
- * Accepts: address list
- */
-
- void paddr (a)
- ADDRESS *a;
- {
- if (a) { /* have anything in address? */
- putchar ('('); /* open the address list */
- do { /* for each address */
- putchar ('('); /* open the address */
- pstring (a->personal); /* personal name */
- putchar (' ');
- pstring (a->adl); /* at-domain-list */
- putchar (' ');
- pstring (a->mailbox); /* mailbox */
- putchar (' ');
- pstring (a->host); /* domain name of mailbox's host */
- putchar (')'); /* terminate address */
- } while (a = a->next); /* until end of address */
- putchar (')'); /* close address list */
- }
- else fputs ("NIL",stdout); /* empty address */
- }
-
- /* Count string and space afterwards
- * Accepts: string
- */
-
- long cstring (s)
- char *s;
- {
- char tmp[20];
- char c,*t;
- long i;
- if (t = s) { /* is there a string? */
- /* yes, search for specials */
- while (c = *t++) if (c == '"' || c == '{' || c == '\015' || c == '\012' ||
- c == '%' || c == '\\') break;
- if (c) { /* must use literal string */
- sprintf (tmp,"{%d}\015\012",i = strlen (s));
- return strlen (tmp) + i + 1;
- }
- else return 3 + strlen (s); /* quoted string */
- }
- else return 4; /* NIL plus space */
- }
-
-
- /* Count address list and space afterwards
- * Accepts: address list
- */
-
- long caddr (a)
- ADDRESS *a;
- {
- long i = 3; /* open, close, and space */
- /* count strings in address list */
- if (a) do i += 1 + cstring (a->personal) + cstring (a->adl) +
- cstring (a->mailbox) + cstring (a->host);
- while (a = a->next); /* until end of address */
- else i = 4; /* NIL plus space */
- return i; /* return the count */
- }
-
- /* Co-routines from MAIL library */
-
-
- /* Message matches a search
- * Accepts: IMAP2 stream
- * message number
- */
-
- void mm_searched (stream,msgno)
- MAILSTREAM *stream;
- long msgno;
- {
- /* nothing to do here */
- }
-
-
- /* Message exists (mailbox)
- i.e. there are that many messages in the mailbox;
- * Accepts: IMAP2 stream
- * message number
- */
-
- void mm_exists (stream,number)
- MAILSTREAM *stream;
- long number;
- {
- /* note change in number of messages */
- printf ("* %d EXISTS\015\012",(nmsgs = number));
- recent = -1; /* make sure fetch new recent count */
- }
-
-
- /* Message expunged
- * Accepts: IMAP2 stream
- * message number
- */
-
- void mm_expunged (stream,number)
- MAILSTREAM *stream;
- long number;
- {
- printf ("* %d EXPUNGE\015\012",number);
- }
-
-
- /* Mailbox found
- * Accepts: Mailbox name
- */
-
- void mm_mailbox (string)
- char *string;
- {
- printf ("* MAILBOX %s\015\012",string);
- }
-
-
- /* BBoard found
- * Accepts: BBoard name
- */
-
- void mm_bboard (string)
- char *string;
- {
- printf ("* BBOARD %s\015\012",string);
- }
-
- /* Notification event
- * Accepts: IMAP2 stream
- * string to log
- * error flag
- */
-
- void mm_notify (stream,string,errflg)
- MAILSTREAM *stream;
- char *string;
- long errflg;
- {
- mm_log (string,errflg); /* just do mm_log action */
- }
-
-
- /* Log an event for the user to see
- * Accepts: string to log
- * error flag
- */
-
- void mm_log (string,errflg)
- char *string;
- long errflg;
- {
- switch (errflg) { /* action depends upon the error flag */
- case NIL: /* information message, set as OK response */
- if (response == win) { /* only if no other response yet */
- response = altwin; /* switch to alternative win message */
- fs_give ((void **) &lsterr);
- lsterr = cpystr (string); /* copy string for later use */
- }
- break;
- case PARSE: /* parse glitch, output unsolicited OK */
- printf ("* OK %s\015\012",string);
- break;
- case WARN: /* warning, output unsolicited NO (kludge!) */
- if (strcmp (string,"Mailbox is empty")) printf ("* NO %s\015\012",string);
- break;
- case ERROR: /* error that broke command */
- default: /* default should never happen */
- response = lose; /* set fatality */
- fs_give ((void **) &lsterr);/* flush old error */
- lsterr = cpystr (string); /* note last error */
- break;
- }
- }
-
-
- /* Log an event to debugging telemetry
- * Accepts: string to log
- */
-
- void mm_dlog (string)
- char *string;
- {
- mm_log (string,WARN); /* shouldn't happen normally */
- }
-
- /* Get user name and password for this host
- * Accepts: host name
- * where to return user name
- * where to return password
- * trial count
- */
-
- void mm_login (host,username,password,trial)
- char *host;
- char *username;
- char *password;
- long trial;
- {
- strcpy (username,user); /* set user name */
- strcpy (password,pass); /* and password */
- }
-
- /* About to enter critical code
- * Accepts: stream
- */
-
- void mm_critical (stream)
- MAILSTREAM *stream;
- {
- /* Not doing anything here for now */
- }
-
-
- /* About to exit critical code
- * Accepts: stream
- */
-
- void mm_nocritical (stream)
- MAILSTREAM *stream;
- {
- /* Not doing anything here for now */
- }
-
-
- /* Disk error found
- * Accepts: stream
- * system error code
- * flag indicating that mailbox may be clobbered
- * Returns: abort flag
- */
-
- long mm_diskerror (stream,errcode,serious)
- MAILSTREAM *stream;
- long errcode;
- long serious;
- {
- if (serious) { /* try your damnest if clobberage likely */
- printf ("* BAD Retrying to fix probable mailbox damage!\015\012");
- /* make damn sure timeout disabled */
- timer.it_value.tv_sec = timer.it_value.tv_usec = 0;
- setitimer (ITIMER_REAL,&timer,NIL);
- sleep (60); /* give it some time to clear up */
- return NIL;
- }
- /* otherwise die before more damage is done */
- printf ("* BYE Aborting due to disk error %s\015\012",strerror (errcode));
- return T;
- }
-
-
- /* Log a fatal error event
- * Accepts: string to log
- */
-
- void mm_fatal (string)
- char *string;
- {
- mm_log (string,ERROR); /* shouldn't happen normally */
- }
-